/**
 * @file ljj_spi.hpp
 *
 * Driver for the extern SPI bus to another mcu.
 *
 * @author   健宝 	<JohnLiuljj@163.com>
 */


#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/defines.h>
#include <px4_platform_common/getopt.h>
#include <px4_platform_common/module.h>
#include <lib/perf/perf_counter.h>
#include <drivers/drv_hrt.h>
#include <drivers/device/spi.h>
#include <px4_platform_common/i2c_spi_buses.h>
#include <unistd.h>
#include <stdio.h>

#include <uORB/uORB.h>
#include <uORB/Publication.hpp>
#include <uORB/Subscription.hpp>
#include <uORB/SubscriptionCallback.hpp>
#include <uORB/topics/muc_recive.h>
#include <uORB/topics/muc_send.h>


#include <px4_platform_common/module_params.h>
#include <uORB/topics/parameter_update.h>
#include <uORB/Subscription.hpp>

// #include <uORB/topics/debug_key_value.h>
// #include <uORB/topics/debug_value.h>
// #include <uORB/topics/debug_vect.h>
// #include <uORB/topics/debug_array.h>

class LJJSPI : public device::SPI, public I2CSPIDriver<LJJSPI>, public ModuleParams
{
public:

	/**
	 * @brief It will be called in  (// I2CSPIDriverBase *LJJSPI::instantiate //).
	 */
	LJJSPI(I2CSPIBusOption bus_option, int bus, int32_t device, int bus_frequency, spi_mode_e spi_mode);


	/**
	 * @brief Initialize the object and bus on the work queue thread - this will also probe for the device.
	 *
	 * @brief It will be called in (// int I2CSPIDriverBase::module_start //) as : I2CSPIDriverBase *instance = initializer_data.instance.
	 */
	static I2CSPIDriverBase *instantiate(const BusCLIArguments &cli, const BusInstanceIterator &iterator,
					     int runtime_instance);


	/**
	 * @brief Initialise the driver and make it ready for use.
	 *
	 * @brief This function inherited from class __EXPORT SPI : public CDev.
	 *
	 * @brief It will be called by (// I2CSPIDriverBase *LJJSPI::instantiate //) as : if (OK != instance->init()).
	 */
	int		init() override;


	/**
	 * @brief Print out the current working status : bus working status and event running status .
	 *
	 *  @brief This function inherited from class I2CSPIDriverBase virtual void print_status();
	 */
	void		print_status() override;


	/**
	 * @brief This is what we well do in schedule cycle.
	 *
	 * @brief Function (// void Run() final //) in class I2CSPIDriver .
	 *
	 * @brief This function will be called by function (// void Run() final //) in class I2CSPIDriver  as : static_cast<T *>(this)->RunImpl() .
	 *
	 * @brief Do (// ScheduleOnInterval() / ScheduleNow() / ScheduleDelayed() //) will call   (// void Run() final //) .
	 */
	void		RunImpl();


	virtual ~LJJSPI();
	static void     print_usage();

private:

	/**
	 * @brief  Record the performance counter, see perf_begin() and perf_end() in function RunImpl().
	 */
	perf_counter_t		_sample_perf;


	/**
	 * @brief  Just return OK in this function.
	 *
	 * @brief This function inherited from class __EXPORT SPI : public CDev.
	 *
	 * @brief This function will be called by SPI::init() .
	 */
	int		probe() override;


	/**
	 * @brief Start automatic Schedule.
	 *
	 * @brief In this program it works like : start() --> ScheduleOnInterval() --> Run() -->RunImpl() .
	 */
	void			start();


	/**
	 * @brief Write and read a register in the LJJSPI
	 *
	 * @param reg		The register to write, uint8_t type.
	 *
	 * @param value		The new value to write, uint16_t type.
	 *
	 * @return		The value that was read, uint16_t type.
	 */
	uint16_t	read_write(uint8_t reg, uint16_t value);

	/**
	 * @brief Write a register only in the LJJSPI
	 *
	 * @param reg		The register to write, uint8_t type.
	 */
	void  writeOnly(uint8_t reg, uint16_t value);



	/**
	 * Check for parameter changes and update them if needed.
	 */
	void parameters_update();

	DEFINE_PARAMETERS(
		(ParamInt<px4::params::LJJ_SPI_SENDONLY>) _ljj_spi_sendonly  /**< example parameter */
	)
	// Subscriptions
	uORB::Subscription _parameter_update_sub{ORB_ID(parameter_update)};
	int sendonly;


	// orb_advert_t pub_dbg_key;
	// struct debug_key_value_s dbg_key;

	uORB::Subscription _muc_send_sub{ORB_ID(muc_send)};
	uORB::Publication<muc_recive_s>	_muc_recive_pub{ORB_ID(muc_recive)};
	struct muc_recive_s	spi_recive{};
	struct muc_send_s	spi_send{};
};













